home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1995…tember: Reference Library / Dev.CD Sep 95 RL / Dev.CD Sep 95 RL.toast / mac / Technical Documentation / develop / develop Issue 22 code / PCI Driver Sample / NCR_DriverProject / Src / LogLibrary.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-04-07  |  35.1 KB  |  1,209 lines  |  [TEXT/MPCC]

  1. /*                                    LogLibrary.c                                    */
  2. /*
  3.  * LogLibrary.c
  4.  * Copyright © 1992-95 Apple Computer Inc. All Rights Reserved.
  5.  * Programmed by Martin Minow,
  6.  *    Internet:    minow@apple.com
  7.  *    AppleLink:    MINOW
  8.  *
  9.  * Edit History
  10.  * This library implements a drop-in logging capability for device drivers,
  11.  * callback functions, applications, and all other Power Macintosh code segments
  12.  * running under a version of system software that supports the System Name Registry
  13.  * and Driver Services libraries defined in Designing PCI Cards and Drivers for
  14.  * Power Macintosh Computers.
  15.  *
  16.  * The overall philosophy is that an application or driver allocates a record in
  17.  * the resident pool that contains a small preamble and one or more short blocks of
  18.  * data. The driver logs data to the log area, where each log record contains an
  19.  * identification value, a timestamp and up to eight longwords of data. The data
  20.  * entry is self-formatting, so a generic log display application may be written.
  21.  *
  22.  * To permit logging from primary interupt level (which precludes using Software
  23.  * Interrupts), the log record common area is protected by a critical section
  24.  * (test and set) variable. The log is "lossy" in that failure to enter the
  25.  * critical section will lose data, but will not stall or block the caller.
  26.  *
  27.  * This function will crash (or fail to load) if Driver Services and/or Name
  28.  * Registry functions are unavailable.
  29.  *
  30.  * The LogData library may be linked into a PCI Device Driver: it does not
  31.  * call any Macintosh Toolbox functions.
  32.  *
  33.  * If compiled under Power PC (native), LogLibrary generates the actual
  34.  * log support. If compiled for the 68000 architecture, it generates Mixed
  35.  * Mode "glue" routines that will link the 68000 functions to the LogData
  36.  * shared library.
  37.  *
  38.  * Usage:
  39.  *    PowerPC (native):
  40.  *        Include "LogLibrary.h" in all compilations.
  41.  *        Either compile LogLibrary.c or include LogLibrary (shared library).
  42.  *    68000 emulation
  43.  *        Include "LogLibrary.h" in all compilations.
  44.  *        Compile LogLibrary.c (or include an object).
  45.  *        Make LogLibrary known to the executing program, possibly by storing
  46.  *        it in the Extensions folder.
  47.  *
  48.  * Edit History
  49.  * 1995.03.28    MM    CompareAndSwap screw-up.
  50.  * 1995.03.31    MM    Removed UpTime return from CopyLogEntry (only the dcmd needs it)
  51.  *                    Added LogLibraryUpTime to return UpTime in nanoseconds for 68000
  52.  *                    functions.
  53.  *                    ResolveLogLibraryLinkage is now a static function: it was global.
  54.  * 1995.04.07    MM    Some compilers mis-handle functions returning structures. Store
  55.  *                    UpTime returned values in a volatile local variable before using
  56.  *                    them in a function call.
  57.  */
  58.  
  59. #include "LogLibrary.h"
  60. #define LOG    (*logRecordPtr)
  61. #ifndef TEST_DCMD
  62. #ifdef MPW
  63. #define TEST_DCMD        1
  64. #else
  65. #define TEST_DCMD        0
  66. #endif /* MPW */
  67. #endif /* TEST_DCMD undefined */
  68. #if GENERATINGPOWERPC
  69. #define GENERATE_GLUE    0    /* Generate the actual library    */
  70. #else
  71. #define GENERATE_GLUE    1    /* Generate Mixed Mode glue        */
  72. #if TEST_DCMD
  73. /*
  74.  * For testing with the dcmd only
  75.  */
  76. extern void                    PutSigned(
  77.         SInt32                    value
  78.     );
  79. extern void                    PutPascalString(
  80.         ConstStr255Param        datum
  81.     );
  82. extern void                        PutLine(void);
  83. #endif /* dcmd testing */
  84. #endif /* Generating Mixed Mode glue */
  85.  
  86. #ifndef TRUE
  87. #define TRUE    1
  88. #define FALSE    0
  89. #endif
  90. #define EOS        '\0'
  91. /*
  92.  * "name" is used by the Name Registry.
  93.  */
  94. #define kReservedPropertyName    "name"
  95.  
  96.  
  97. #if GENERATE_GLUE
  98. #ifndef THINK_C /* Temp until headers stabalize */
  99. #include <MixedMode.h>
  100. #include <CodeFragments.h>
  101. #endif
  102.  
  103. /*
  104.  * Definitions for the Glue library.
  105.  */
  106. #define kLogLinkFailed            ((UniversalProcPtr) (-1L))
  107.  
  108. typedef pascal LogRecordPtr (*MakeLogRecordProcPtr)
  109.                                 (const LogRecordNamePtr, UInt32);
  110. typedef pascal LogRecordPtr    (*GetLogRecordProcPtr)
  111.                                 (const LogRecordNamePtr);
  112. typedef pascal OSErr        (*StoreLogEntryProcPtr)
  113.                                 (LogRecordPtr, const LogEntryPtr);
  114. typedef pascal OSErr        (*ReadLogEntryProcPtr)
  115.                                 (LogRecordPtr, LogEntryPtr);
  116. typedef pascal Boolean32    (*EnableLogRecordProcPtr)
  117.                                 (LogRecordPtr, Boolean32);
  118. typedef pascal Boolean32    (*PreserveLogRecordProcPtr)
  119.                                 (LogRecordPtr, Boolean32);
  120. typedef pascal UInt32        (*GetLogSemaphoreLostCounterProcPtr)
  121.                                 (LogRecordPtr);
  122. typedef pascal OSErr        (*LogRecordIterateCreateProcPtr)
  123.                                 (LogRecordIterPtr);
  124. typedef pascal void            (*LogRecordIterateDisposeProcPtr)
  125.                                 (LogRecordIterPtr);
  126. typedef pascal LogRecordPtr    (*LogRecordIterateProcPtr)
  127.                                 (LogRecordIterPtr);
  128. typedef pascal OSErr        (*CopyLogEntryProcPtr)            /* DCMD only        */
  129.                                 (LogRecordPtr, UInt32, LogEntryPtr);
  130. typedef pascal OSErr        (*CopyLogRecordProcPtr)            /* DCMD only        */
  131.                                 (const LogRecordPtr, LogRecordPtr);
  132. typedef pascal void            (*LogLibraryUpTimeProcPtr)        /* DCMD only        */
  133.                                 (Nanoseconds *);
  134. typedef pascal void            (*LogLibraryAbsoluteToNanosecondsProcPtr)
  135.                                 (const AbsoluteTime *sourcePtr, Nanoseconds *resultPtr);
  136. /* */
  137. static OSErr                ResolveLogLibraryLinkage(
  138.         ConstStr255Param        symbolRDName,
  139.         UniversalProcPtr        *uppPtr
  140.     );
  141. #else /* The real library */
  142. /*
  143.  * These are Routine Descriptors for the functions that are always in Power PC
  144.  * native code, but are called from glue routines. Note that the _rd... symbols
  145.  * must be global so that they can be resolved by the 68000 code. Hmm, is this
  146.  * the correct solution?
  147.  */
  148. enum {
  149.     uppMakeLogRecordProcInfo = kPascalStackBased
  150.         | RESULT_SIZE(SIZE_CODE(sizeof (LogRecordPtr)))
  151.         | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(const LogRecordNamePtr)))
  152.         | STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof (UInt32)))
  153. };
  154. const RoutineDescriptor    _rdMakeLogRecord =
  155.     BUILD_ROUTINE_DESCRIPTOR(uppMakeLogRecordProcInfo, MakeLogRecord);
  156. /* */
  157. enum {
  158.     uppGetLogRecordPtrProcInfo = kPascalStackBased
  159.         | RESULT_SIZE(SIZE_CODE(sizeof (LogRecordPtr)))
  160.         | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(const LogRecordNamePtr)))
  161. };
  162. const RoutineDescriptor    _rdGetLogRecordPtr =
  163.     BUILD_ROUTINE_DESCRIPTOR(uppGetLogRecordPtrProcInfo, GetLogRecordPtr);
  164. /* */
  165. enum {
  166.     uppStoreLogEntryProcInfo = kPascalStackBased
  167.         | RESULT_SIZE(SIZE_CODE(sizeof (OSErr)))
  168.         | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof (LogRecordPtr)))
  169.         | STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof (LogEntryPtr)))
  170. };
  171. const RoutineDescriptor    _rdStoreLogEntry =
  172.     BUILD_ROUTINE_DESCRIPTOR(uppStoreLogEntryProcInfo, StoreLogEntry);
  173. /* */
  174. enum {
  175.     uppReadLogEntryProcInfo = kPascalStackBased
  176.         | RESULT_SIZE(SIZE_CODE(sizeof (OSErr)))
  177.         | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof (LogRecordPtr)))
  178.         | STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof (LogEntryPtr)))
  179. };
  180. const RoutineDescriptor    _rdReadLogEntry =
  181.     BUILD_ROUTINE_DESCRIPTOR(uppReadLogEntryProcInfo, ReadLogEntry);
  182. /* */
  183. enum {
  184.     uppEnableLogRecordProcInfo = kPascalStackBased
  185.         | RESULT_SIZE(SIZE_CODE(sizeof (Boolean32)))
  186.         | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof (LogRecordPtr)))
  187.         | STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof (Boolean32)))
  188. };
  189. const RoutineDescriptor _rdEnableLogRecord =
  190.     BUILD_ROUTINE_DESCRIPTOR(uppEnableLogRecordProcInfo, EnableLogRecord);
  191. /* */
  192. enum {
  193.     uppPreserveLogRecordProcInfo = kPascalStackBased
  194.         | RESULT_SIZE(SIZE_CODE(sizeof (Boolean32)))
  195.         | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof (LogRecordPtr)))
  196.         | STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof (Boolean32)))
  197. };
  198. const RoutineDescriptor _rdPreserveLogRecord =
  199.     BUILD_ROUTINE_DESCRIPTOR(uppPreserveLogRecordProcInfo, PreserveLogRecord);
  200. /* */
  201. enum {
  202.     uppGetLogSemaphoreLostCounterProcInfo = kPascalStackBased
  203.         | RESULT_SIZE(SIZE_CODE(sizeof (UInt32)))
  204.         | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof (LogRecordPtr)))
  205. };
  206. const RoutineDescriptor _rdGetLogSemaphoreLostCounter =
  207.     BUILD_ROUTINE_DESCRIPTOR(
  208.         uppGetLogSemaphoreLostCounterProcInfo,
  209.         GetLogSemaphoreLostCounter
  210.     );
  211. /* */
  212. enum {
  213.     uppLogRecordIterateCreateProcInfo = kPascalStackBased
  214.         | RESULT_SIZE(SIZE_CODE(sizeof (OSErr)))
  215.         | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof (LogRecordIterPtr)))
  216. };
  217. const RoutineDescriptor _rdLogRecordIterateCreate =
  218.     BUILD_ROUTINE_DESCRIPTOR(
  219.         uppLogRecordIterateCreateProcInfo,
  220.         LogRecordIterateCreate
  221.     );
  222. /* */
  223. enum {
  224.     uppLogRecordIterDisposeProcInfo = kPascalStackBased
  225.         | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof (LogRecordIterPtr)))
  226. };
  227. const RoutineDescriptor _rdLogRecordIterateDispose =
  228.     BUILD_ROUTINE_DESCRIPTOR(
  229.         uppLogRecordIterDisposeProcInfo,
  230.         LogRecordIterateDispose
  231.     );
  232. /* */
  233. enum {
  234.     uppLogRecordIterateProcInfo = kPascalStackBased
  235.         | RESULT_SIZE(SIZE_CODE(sizeof (LogRecordPtr)))
  236.         | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof (LogRecordIterPtr)))
  237. };
  238. const RoutineDescriptor _rdLogRecordIterate =
  239.     BUILD_ROUTINE_DESCRIPTOR(
  240.         uppLogRecordIterateProcInfo,
  241.         LogRecordIterate
  242.     );
  243.  
  244. /*
  245.  * These are for the primary use of the DCMD.
  246.  */
  247. enum {
  248.     uppCopyLogEntryProcInfo = kPascalStackBased
  249.         | RESULT_SIZE(SIZE_CODE(sizeof (OSErr)))
  250.         | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof (LogRecordPtr)))
  251.         | STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof (UInt32)))
  252.         | STACK_ROUTINE_PARAMETER(3, SIZE_CODE(sizeof (LogEntryPtr)))
  253. };
  254. const RoutineDescriptor    _rdCopyLogEntry =
  255.     BUILD_ROUTINE_DESCRIPTOR(uppCopyLogEntryProcInfo, CopyLogEntry);
  256.         
  257. enum {
  258.     uppCopyLogRecordProcInfo = kPascalStackBased
  259.         | RESULT_SIZE(SIZE_CODE(sizeof (OSErr)))
  260.         | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof (LogRecordPtr)))
  261.         | STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof (LogRecordPtr)))
  262. };
  263. const RoutineDescriptor    _rdCopyLogRecordInfo =
  264.     BUILD_ROUTINE_DESCRIPTOR(uppCopyLogRecordProcInfo, CopyLogRecordInfo);
  265.  
  266. enum {
  267.     uppLogLibraryUpTimeProcInfo = kPascalStackBased
  268.         | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof (Nanoseconds *)))
  269. };
  270. const RoutineDescriptor _rdLogLibraryUpTime =
  271.     BUILD_ROUTINE_DESCRIPTOR(uppLogLibraryUpTimeProcInfo, LogLibraryUpTime);
  272.  
  273. enum {
  274.     uppLogLibraryAbsoluteToNanosecondsProcInfo = kPascalStackBased
  275.         | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof (const AbsoluteTime *)))
  276.         | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof (Nanoseconds *)))
  277. };
  278. const RoutineDescriptor _rdLogLibraryAbsoluteToNanoseconds =
  279.     BUILD_ROUTINE_DESCRIPTOR(uppLogLibraryUpTimeProcInfo, LogLibraryAbsoluteToNanoseconds);
  280.  
  281. /* */
  282. static RegEntryID            gLogEntryID;
  283. typedef enum {
  284.     kFirstCall = 0,
  285.     kLogEntryOK,
  286.     kLogEntryFailed
  287. } FoundLogEntryStatus;
  288. static FoundLogEntryStatus    gFoundLogEntryStatus;
  289.  
  290. static LogRecordPtr            FindLogRecordPtr(
  291.         const LogRecordNamePtr    logRecordNamePtr
  292.     );
  293. static LogRecordPtr            CreateLogRecord(
  294.         const LogRecordNamePtr    logRecordNamePtr,        /* Driver Log name            */
  295.         UInt32                    nEntries                /* Number of Log entries    */
  296.     );
  297. static Boolean                FindOrCreateLogRegistryEntryID(void);
  298.  
  299. #endif /* GENERATE_GLUE */
  300.  
  301. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  302.  * MakeLogRecord
  303.  *
  304.  * The first time this function is called after the system is started, it creates a
  305.  * log record for this name. The log is initially enabled, and deletes overflow at the
  306.  * start. It thus retains the *end* of the log -- this is useful for ongoing logging,
  307.  * but may lose the start of a disaster sequence (as it records the flow of errors
  308.  * through the system, rather than the intial cause.
  309.  *
  310.  * Returns the LogRecordPtr for this log, or NULL if unsuccessful.
  311.  *
  312.  * This function must be called in a context that can allocate memory. The first
  313.  * call from a 68000 architecture module must be able to load a shared library.
  314.  */
  315. pascal LogRecordPtr
  316. MakeLogRecord(
  317.         const LogRecordNamePtr    logRecordNamePtr,        /* Log name (C-string)        */
  318.         UInt32                    nEntries                /* Number of Log entries    */
  319.     )
  320. {
  321.         LogRecordPtr            logRecordPtr;            /* This log record            */
  322. #if GENERATE_GLUE
  323.         MakeLogRecordProcPtr    upp;
  324.  
  325.         if (ResolveLogLibraryLinkage(
  326.                     "\p_rdMakeLogRecord",
  327.                     (UniversalProcPtr *) &upp)
  328.                 != noErr)
  329.             logRecordPtr = NULL;
  330.         else {
  331.             logRecordPtr = (*upp)(logRecordNamePtr, nEntries);
  332.         }
  333. #else    
  334.         logRecordPtr = CreateLogRecord(logRecordNamePtr, nEntries);
  335.         /*
  336.          * This is either a new log record or one already created. Grab the
  337.          * semaphore (to protect against an asynchronous process trying to log
  338.          * to us) and initialze the log record if it is not already present.
  339.          */
  340.         if (CompareAndSwap(0, 1, &LOG.semaphore) == FALSE)    /* Grab semaphore        */
  341.             IncrementAtomic((SInt32 *) &LOG.lostLockCounter); /* Oops, it's busy    */
  342.         else {                                                /* Nope, we got it        */
  343.             if (LOG.entryMaxIndex == 0) {
  344.                 /*
  345.                  * Fresh start. Save the logName, set the flag. All other fields
  346.                  * are zero.
  347.                  */
  348.                 LOG.entryMaxIndex = nEntries + 1;
  349.                 LOG.sequenceCounter = 1;
  350.                 CStrNCopy(
  351.                     LOG.logName,
  352.                     (char *) logRecordNamePtr,
  353.                     sizeof LOG.logName - 1
  354.                 );
  355.                 LOG.flags = ( (1 * kLogDataEnabledMask)
  356.                             | (0 * kLogDataPreserveFirstMask)
  357.                             );
  358.             }
  359.             LOG.semaphore = 0;                                /* Free the semaphore    */
  360.         }
  361. #endif /* GENERATE_GLUE */
  362.         return (logRecordPtr);
  363. }
  364.  
  365. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  366.  * GetLogRecordPtr
  367.  *
  368.  * Find the address of the LogRecord in the System Registry.
  369.  *
  370.  * The first call from a 68000 architecture module must be able to load a shared
  371.  * library.
  372.  */
  373. pascal LogRecordPtr
  374. GetLogRecordPtr(
  375.         const LogRecordNamePtr    logRecordNamePtr        /* Log name (C-string)        */
  376.     )
  377. {
  378.         LogRecordPtr            logRecordPtr;            /* This log record            */
  379. #if GENERATE_GLUE
  380.         GetLogRecordProcPtr        upp;
  381.  
  382.         if (ResolveLogLibraryLinkage(
  383.                     "\p_rdGetLogRecordPtr",
  384.                     (UniversalProcPtr *) &upp)
  385.                 != noErr)
  386.             logRecordPtr = NULL;
  387.         else {
  388.             logRecordPtr = (*upp)(logRecordNamePtr);
  389.         }
  390. #else
  391.         logRecordPtr = FindLogRecordPtr(logRecordNamePtr);
  392. #endif /* GENERATE_GLUE */
  393.         return (logRecordPtr);
  394. }
  395.  
  396. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  397.  * CopyLogRecordInfo
  398.  *
  399.  * This function copies the permanent part of the LogRecord (srcLogRecordPtr) to a
  400.  * caller-designated area (dstLogRecordPtr). It is only for the benefit of the DCMD.
  401.  * It returns noErr if successful, paramErr if either the source or destination parameters
  402.  * are incorrect, or a Shared Library Manager error. This function ignores the interlock
  403.  * semaphore. Thus, it may return inconstent data. It does not copy the first LogRecordEntry.
  404.  *
  405.  * Only the DCMD is permitted to call this function!
  406.  */
  407. pascal OSErr
  408. CopyLogRecordInfo(
  409.         const LogRecordPtr        srcLogRecordPtr,
  410.         LogRecordPtr            dstLogRecordPtr
  411.     )
  412. {
  413.         OSErr                    status;
  414. #if GENERATE_GLUE
  415.         CopyLogRecordProcPtr    upp;
  416.  
  417.         status = ResolveLogLibraryLinkage(
  418.                     "\p_rdCopyLogRecordInfo",
  419.                     (UniversalProcPtr *) &upp);
  420.         if (status == noErr)
  421.             status = (*upp)(srcLogRecordPtr, dstLogRecordPtr);
  422. #else    
  423.         if (srcLogRecordPtr == NULL || dstLogRecordPtr == NULL)
  424.             status = paramErr;
  425.         else {
  426.             BlockCopy(
  427.                 srcLogRecordPtr,
  428.                 dstLogRecordPtr,
  429.                 sizeof (LogRecord) - sizeof (LogEntryRecord)
  430.             );
  431.             status = noErr;
  432.         }
  433. #endif /* GENERATE_GLUE */
  434.         return (status);
  435. }
  436.  
  437. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  438.  * (LogString)
  439.  *
  440.  * This is a function version of the LogEntryString macro.
  441.  */
  442. pascal OSErr
  443. (LogString)(
  444.         LogRecordPtr            logRecordPtr,            /* This log record            */
  445.         OSType                    idCode,                    /* Entry identifier            */
  446.         ConstStr255Param        string                    /* The datum                */
  447.     )
  448. {
  449.         OSErr                    status;
  450.  
  451.         status = WriteLogEntry(logRecordPtr, idCode, LogStringFormat, string);
  452.         return (status);
  453. }
  454.  
  455. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  456.  * (LogStatusString)
  457.  *
  458.  * This is a function version of the LogDataStatusString macro.
  459.  */
  460. pascal OSErr
  461. (LogStatusString)(
  462.         LogRecordPtr            logRecordPtr,            /* This log record            */
  463.         OSType                    idCode,                    /* Entry identifier            */
  464.         OSErr                    callerStatus,            /* Status error code        */
  465.         ConstStr255Param        string                    /* The datum                */
  466.     )
  467. {
  468.         OSErr                    status;
  469.  
  470.         status = WriteLogEntry(
  471.                 logRecordPtr,
  472.                 idCode,
  473.                 LogStatusFormat,
  474.                 (signed long) callerStatus,
  475.                 string
  476.             );
  477.         return (status);
  478. }
  479.  
  480. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  481.  * WriteLogEntry
  482.  *
  483.  * This function logs data if logging is enabled.
  484.  *        idCode        A user-controlled value, by convention an OSType (4-byte
  485.  *                    character), that identifies this entry. The display program
  486.  *                    prints it.
  487.  *        format        The format of the remaining data: kLogFormatString if the
  488.  *                    datum is a pascal string, otherwise, it is as created by the
  489.  *                    LogFormat macro.
  490.  *        ...            Additional data as needed. These values must be cast to
  491.  *                    longwords to prevent ThinkC/MPW incompatibilities.
  492.  * Note: The MixedMode Manager does not support variable-length argument lists.
  493.  * Hence, this function is always in the "current" architecture.
  494.  */
  495. OSErr
  496. WriteLogEntry(
  497.         LogRecordPtr            logRecordPtr,            /* This log record            */
  498.         OSType                    idCode,
  499.         UInt32                    format,
  500.         ...
  501.     )
  502. {
  503.         va_list                    argPtr;
  504.         register UInt32            *destPtr;
  505.         LogEntryRecord            theEntry;
  506.         UInt16                    maxString;
  507.         register UInt16            stringLength;
  508.         register UInt16            i;
  509.         UInt16                    thisFormat;
  510.         StringPtr                theString;
  511.         OSErr                    status;
  512. #define ENTRY    (theEntry)
  513.  
  514.         if (logRecordPtr == NULL || (LOG.flags & kLogDataEnabledMask) == 0)
  515.             status = noErr;
  516.         else {
  517.             ENTRY.idCode = idCode;
  518.             ENTRY.format = format;
  519.             va_start(argPtr, format);
  520.             destPtr = ENTRY.data;
  521.             maxString = sizeof (ENTRY.data);
  522.             while (maxString > 0) {
  523.                 thisFormat = format & kLogFormatMask;
  524.                 switch (thisFormat) {
  525.                 case kLogFormatEnd:
  526.                     goto exitLoop;
  527.                 case kLogFormatString:
  528.                     theString = va_arg(argPtr, StringPtr);
  529.                     if (theString == NULL)
  530.                         theString = "\p{null}";
  531.                     stringLength = theString[0];
  532.                     if (stringLength >= maxString)
  533.                         stringLength = maxString - 1;
  534.                     for (i = 1; i <= stringLength; i++)
  535.                         ((Ptr) destPtr)[i] = theString[i];
  536.                     ((Ptr) destPtr)[0] = stringLength;
  537.                     goto exitLoop;
  538.                 default:                /* Signed or unsigned long value            */
  539.                     *destPtr++ = va_arg(argPtr, unsigned long);
  540.                     format >>= kLogFormatShift;
  541.                     maxString -= sizeof (unsigned long);
  542.                     break;
  543.                 }
  544.             }
  545. exitLoop:    va_end(nextArg);
  546.             status = StoreLogEntry(logRecordPtr, &theEntry);
  547.         } /* If the LogData record exists */
  548.         return (status);
  549. #undef ENTRY
  550. }
  551.  
  552. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  553.  * StoreLogEntry
  554.  *
  555.  * Store a formatted LogEntryRecord in the log. This is the only routine that
  556.  * writes the log entry. Normally, it is only called by WriteLogData.
  557.  */
  558. pascal OSErr
  559. StoreLogEntry(
  560.         LogRecordPtr            logRecordPtr,            /* This log record            */
  561.         const LogEntryPtr        logEntryPtr                /* Gets this entry            */
  562.     )
  563. {
  564.         OSErr                    status;
  565. #if GENERATE_GLUE
  566.         StoreLogEntryProcPtr    upp;
  567.  
  568.         status = ResolveLogLibraryLinkage(
  569.                     "\p_rdStoreLogEntry",
  570.                     (UniversalProcPtr *) &upp
  571.                 );
  572.         if (status == noErr)
  573.             status = (*upp)(logRecordPtr, logEntryPtr);
  574. #else    
  575.         UInt32                    putIndex;
  576.         UInt32                    getIndex;
  577. #define ENTRY    (*logEntryPtr)
  578.  
  579.         if (logRecordPtr == NULL || (LOG.flags & kLogDataEnabledMask) == 0)
  580.             status = noErr;
  581.         else {
  582.             ENTRY.eventTime = UpTime();
  583.             ENTRY.sequence = IncrementAtomic((SInt32 *) &LOG.sequenceCounter);
  584.             if (CompareAndSwap(0, 1, &LOG.semaphore) == FALSE) { /* Grab semaphore    */
  585.                 IncrementAtomic((SInt32 *) &LOG.lostLockCounter); /* Oops, it's busy*/
  586.                 status = fBsyErr;                                /* Return "busy"    */
  587.             }
  588.             else {                                                /* Nope, we got it    */
  589.                 /*
  590.                  * The ring buffer is designed so that put == get implies empty
  591.                  * and pointers are always incremented before use.
  592.                  */
  593.                 putIndex = LOG.entryPutIndex + 1;
  594.                 if (putIndex >= LOG.entryMaxIndex) {
  595.                     putIndex = 0;
  596.                     LOG.flags |= kLogDataWrapAroundMask;
  597.                 }
  598.                 if (putIndex == LOG.entryGetIndex) {        /* Did it fill?        */
  599.                     if ((LOG.flags & kLogDataPreserveFirstMask) != 0)
  600.                         status = writErr;                    /* Keeping first    */
  601.                     else {
  602.                         /*
  603.                          * We want to retain the latest entry. Do this by
  604.                          * advancing the "get" pointer as if the earliest entry
  605.                          * has been read. Then jump around the if bracket to store
  606.                          * this datum.
  607.                          */
  608.                         getIndex = LOG.entryGetIndex + 1;
  609.                         if (getIndex >= LOG.entryMaxIndex)
  610.                             getIndex = 0;
  611.                         LOG.entryGetIndex = getIndex;
  612.                         goto storeDatum;
  613.                     }
  614.                 }
  615.                 else {
  616. storeDatum:            LOG.entries[putIndex] = ENTRY;
  617.                     LOG.entryPutIndex = putIndex;
  618.                     status = noErr;                                /* Data stored ok    */
  619.                 }
  620.                 LOG.semaphore = 0;                                /* Free semaphore    */
  621.             }
  622.         }
  623. #endif /* GENERATE_GLUE */
  624.         return (status);
  625. }
  626.  
  627. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  628.  * ReadLogEntry
  629.  *
  630.  * Read the next LogRecord entry. This returns a copy of the entry, if one is
  631.  * available. The following status may be returned:
  632.  *    noErr        Valid data was returned.
  633.  *    readErr        No data is available.
  634.  *    fBsyErr        The semaphore was locked by another function (presumable writing
  635.  *                into the log). Try again later.
  636.  *    other        Code Fragment error.
  637.  */
  638. pascal OSErr
  639. ReadLogEntry(
  640.         LogRecordPtr            logRecordPtr,            /* This log record            */
  641.         LogEntryPtr                thisLogEntry            /* Store entry here            */
  642.     )
  643. {
  644.         OSErr                    status;
  645. #if GENERATE_GLUE
  646.         ReadLogEntryProcPtr        upp;
  647.  
  648.         status = ResolveLogLibraryLinkage(
  649.                     "\p_rdReadLogEntry",
  650.                     (UniversalProcPtr *) &upp
  651.                 );
  652.         if (status == noErr)
  653.             status = (*upp)(logRecordPtr, thisLogEntry);
  654. #else    
  655.         UInt32                    getIndex;
  656.  
  657.         status = readErr;                                    /* Presume no data        */
  658.         if (logRecordPtr != NULL && thisLogEntry != NULL) {
  659.             if (CompareAndSwap(0, 1, &LOG.semaphore) == FALSE) { /* Grab semaphore    */
  660.                 IncrementAtomic((SInt32 *) &LOG.lostLockCounter); /* Oops, it's busy*/
  661.                 status = fBsyErr;                                /* Inform caller    */
  662.             }
  663.             else {                                                /* Nope, we got it    */
  664.                 getIndex = LOG.entryGetIndex;
  665.                 if (getIndex != LOG.entryPutIndex) {            /* Not empty?        */
  666.                     status = noErr;
  667.                     if (++getIndex >= LOG.entryMaxIndex)
  668.                         getIndex = 0;
  669.                     *thisLogEntry = LOG.entries[getIndex];
  670.                     LOG.entryGetIndex = getIndex;
  671.                 }
  672.                 LOG.semaphore = 0;                                /* Free semaphore    */
  673.             }
  674.         }
  675. #endif /* GENERATE_GLUE */
  676.         return (status);
  677. }
  678.  
  679. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  680.  * CopyLogEntry
  681.  *
  682.  * Copy the specified LogRecord entry. This returns a copy of the entry, return TRUE
  683.  * if it was in range. This is only used by the DCMD to snapshot a LogRecord.
  684.  */
  685. pascal OSErr
  686. CopyLogEntry(
  687.         LogRecordPtr            logRecordPtr,            /* This log record            */
  688.         UInt32                    getIndex,                /* This entry index            */
  689.         LogEntryPtr                thisLogEntry            /* Store entry here            */
  690.     )
  691. {
  692.         OSErr                    status;
  693. #if GENERATE_GLUE
  694.         CopyLogEntryProcPtr        upp;
  695.  
  696.         status = ResolveLogLibraryLinkage(
  697.                     "\p_rdCopyLogEntry",
  698.                     (UniversalProcPtr *) &upp
  699.                 );
  700.         if (status == noErr)
  701.             status = (*upp)(logRecordPtr, getIndex, thisLogEntry);
  702. #else    
  703.         status = readErr;
  704.         if (logRecordPtr != NULL && getIndex < LOG.entryMaxIndex) {
  705.             if (CompareAndSwap(0, 1, &LOG.semaphore) == FALSE) { /* Grab semaphore    */
  706.                 IncrementAtomic((SInt32 *) &LOG.lostLockCounter); /* Oops, it's busy*/
  707.                 status = fBsyErr;                                /* Inform caller    */
  708.             }
  709.             else {                                                /* Nope, we got it    */
  710.                 status = noErr;                                    /* Inform caller    */
  711.                 *thisLogEntry = LOG.entries[getIndex];            /* Store result        */
  712.                 LOG.semaphore = 0;                                /* Free semaphore    */
  713.             }
  714.         }
  715. #endif /* GENERATE_GLUE */
  716.         return (status);
  717. }
  718.  
  719. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  720.  * LogLibraryUpTime
  721.  *
  722.  * Returns UpTime in nanoseconds. This can be called from 68000 code.
  723.  */
  724. pascal void
  725. LogLibraryUpTime(
  726.         Nanoseconds                *resultPtr
  727.     )
  728. {
  729. #if GENERATE_GLUE
  730.         OSErr                    status;
  731.         LogLibraryUpTimeProcPtr    upp;
  732.  
  733.         status = ResolveLogLibraryLinkage(
  734.                     "\p_rdLogLibraryUpTime",
  735.                     (UniversalProcPtr *) &upp
  736.                 );
  737.         if (status == noErr)
  738.             (*upp)(resultPtr);
  739.         else {
  740.             resultPtr->hi = resultPtr->lo = 0;
  741.         }
  742. #else
  743.         volatile AbsoluteTime        now;    /* Prevent a compiler bug    */
  744.  
  745.         now = UpTime();
  746.         *resultPtr = AbsoluteToNanoseconds(now);
  747. #endif /* GENERATE_GLUE */
  748. }
  749.  
  750. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  751.  * LogLibraryAbsoluteToNanoseconds
  752.  *
  753.  * AbsoluteToNanoseconds. This can be called from 68000 code.
  754.  */
  755. pascal void
  756. LogLibraryAbsoluteToNanoseconds(
  757.         const AbsoluteTime        *sourcePtr,
  758.         Nanoseconds                *resultPtr
  759.     )
  760. {
  761. #if GENERATE_GLUE
  762.         OSErr                                    status;
  763.         LogLibraryAbsoluteToNanosecondsProcPtr    upp;
  764.  
  765.         status = ResolveLogLibraryLinkage(
  766.                     "\p_rdLogLibraryAbsoluteToNanoseconds",
  767.                     (UniversalProcPtr *) &upp
  768.                 );
  769.         if (status == noErr)
  770.             (*upp)(sourcePtr, resultPtr);
  771.         else {
  772.             resultPtr->hi = resultPtr->lo = 0;
  773.         }
  774. #else    
  775.         *resultPtr = AbsoluteToNanoseconds(*sourcePtr);
  776. #endif /* GENERATE_GLUE */
  777.  
  778. }
  779.  
  780. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  781.  * EnableLogRecord
  782.  *
  783.  * Enable/disable logging. Returns the old logging state.
  784.  */
  785. pascal Boolean32
  786. EnableLogRecord(
  787.         LogRecordPtr            logRecordPtr,            /* This log record            */
  788.         Boolean32                enableLogging
  789.     )
  790. {
  791.         Boolean32                result;
  792. #if GENERATE_GLUE
  793.         EnableLogRecordProcPtr    upp;
  794.  
  795.         if (ResolveLogLibraryLinkage(
  796.                     "\p_rdEnableLogRecord",
  797.                     (UniversalProcPtr *) &upp)
  798.                 != noErr)
  799.             result = FALSE;
  800.         else {
  801.             result = (*upp)(logRecordPtr, enableLogging);
  802.         }
  803. #else
  804.         UInt32                    oldFlag;
  805.         UInt32                    newFlag;
  806.         
  807.         if (logRecordPtr == NULL)
  808.             oldFlag = 0;
  809.         else {
  810.             do {
  811.                 oldFlag = LOG.flags;
  812.                 if (enableLogging)
  813.                     newFlag = oldFlag | kLogDataEnabledMask;
  814.                 else {
  815.                     newFlag = oldFlag & ~kLogDataEnabledMask;
  816.                 }
  817.             } while (CompareAndSwap(oldFlag, newFlag, &LOG.flags) == FALSE);
  818.         }
  819.         result = ((oldFlag & kLogDataEnabledMask) != 0);
  820. #endif /* GENERATE_GLUE */
  821.         return (result);
  822. }
  823.  
  824. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  825.  * PreserveLogRecord
  826.  *
  827.  * Set the preserveFirst flag. Returns the old flag value. 
  828.  */
  829. pascal Boolean32
  830. PreserveLogRecord(
  831.         LogRecordPtr            logRecordPtr,            /* This log record            */
  832.         Boolean32                preserveFirst
  833.     )
  834. {
  835.         Boolean32                result;
  836. #if GENERATE_GLUE
  837.         PreserveLogRecordProcPtr upp;
  838.  
  839.         if (ResolveLogLibraryLinkage(
  840.                     "\p_rdPreserveLogRecord",
  841.                     (UniversalProcPtr *) &upp)
  842.                 != noErr)
  843.             result = FALSE;
  844.         else {
  845.             result = (*upp)(logRecordPtr, preserveFirst);
  846.         }
  847. #else
  848.         UInt32                    oldFlag;
  849.         UInt32                    newFlag;
  850.  
  851.         if (logRecordPtr == NULL)
  852.             oldFlag = 0;
  853.         else {
  854.             do {
  855.                 oldFlag = LOG.flags;
  856.                 if (preserveFirst)
  857.                     newFlag = oldFlag | kLogDataPreserveFirstMask;
  858.                 else {
  859.                     newFlag = oldFlag & ~kLogDataPreserveFirstMask;
  860.                 }
  861.             } while (CompareAndSwap(oldFlag, newFlag, &LOG.flags) == FALSE);
  862.         }
  863.         result = ((oldFlag & kLogDataPreserveFirstMask) != 0);
  864. #endif /* GENERATE_GLUE */
  865.         return (result);
  866. }
  867.  
  868. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  869.  * GetLogSemaphoreLostCounter
  870.  *
  871.  * Because the log library uses a "lossy" algorithm to maintain exclusive access to
  872.  * the critical section, there is a very slight possibility that two processes will
  873.  * try to access the log record at the same time. In this case, ReadLogEntry will
  874.  * stall (loop) and eventually succeed, while WriteLogEntry will lose the datum, and
  875.  * increment the logLostCounter.
  876.  */
  877. pascal UInt32
  878. GetLogSemaphoreLostCounter(
  879.         LogRecordPtr            logRecordPtr            /* This log record            */
  880.     )
  881. {
  882.         UInt32                    result;
  883. #if GENERATE_GLUE
  884.         GetLogSemaphoreLostCounterProcPtr    upp;
  885.  
  886.         if (ResolveLogLibraryLinkage(
  887.                     "\p_rdGetLogSemaphoreLostCounter",
  888.                     (UniversalProcPtr *) &upp)
  889.                 != noErr)
  890.             result = 0;
  891.         else {
  892.             result = (*upp)(logRecordPtr);
  893.         }
  894. #else
  895.         result = ((logRecordPtr == NULL) ? 0 : LOG.lostLockCounter);
  896. #endif /* GENERATE_GLUE */
  897.         return (result);
  898. }
  899.  
  900. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  901.  * LogRecord utilities.
  902.  *
  903.  * These three functions are used to locate all registered log records. They may be
  904.  * used for a display utility or MacsBug dcmd. Applications call them as follows:
  905.  *
  906.  *    LogRecordIter            cookie;
  907.  *
  908.  *    if (LogRecordIterateCreate(&cookie) == noErr) {
  909.  *        while ((logRecordPtr = LogRecordIterate(&cookie)) != NULL) {
  910.  *            ... Process this LogRecord, the name may be extracted from the record ...
  911.  *        }
  912.  *        LogRecordIterateDispose(&cookie);
  913.  *    }
  914.  */
  915. pascal OSErr
  916. LogRecordIterateCreate(
  917.         LogRecordIterPtr        cookie
  918.     )
  919. {
  920.         OSErr                    status;
  921. #if GENERATE_GLUE
  922.         LogRecordIterateCreateProcPtr upp;
  923.  
  924.         status = ResolveLogLibraryLinkage(
  925.                     "\p_rdLogRecordIterateCreate",
  926.                     (UniversalProcPtr *) &upp
  927.                 );
  928.         if (status == noErr) {
  929.             status = (*upp)(cookie);
  930. if (status != noErr) {
  931.     PutSigned(status);
  932.     PutPascalString("\p: LogRecordIterateCreate failed");
  933.     PutLine();
  934. }
  935.         }
  936. #else
  937.         if (FindOrCreateLogRegistryEntryID() == FALSE)
  938.             status = paramErr;        /* Need correct error    */
  939.         else {
  940.             status = RegistryPropertyIterateCreate(
  941.                         &gLogEntryID,
  942.                         &cookie->propertyIterCookie
  943.                     );
  944.         }
  945. #endif /* GENERATE_GLUE */
  946.         return (status);
  947. }        
  948.  
  949. pascal void
  950. LogRecordIterateDispose(
  951.         LogRecordIterPtr        cookie
  952.     )
  953. {
  954. #if GENERATE_GLUE
  955.         LogRecordIterateDisposeProcPtr upp;
  956.  
  957.         if (ResolveLogLibraryLinkage(
  958.                     "\p_rdLogRecordIterateDispose",
  959.                     (UniversalProcPtr *) &upp) == noErr) {
  960.             (*upp)(cookie);
  961.         }
  962. #else
  963.         RegistryPropertyIterateDispose(&cookie->propertyIterCookie);
  964. #endif /* GENERATE_GLUE */
  965. }
  966.  
  967. pascal LogRecordPtr
  968. LogRecordIterate(
  969.         LogRecordIterPtr        cookie
  970.     )
  971. {
  972.         LogRecordPtr            logRecordPtr;
  973. #if GENERATE_GLUE
  974.         LogRecordIterateProcPtr    upp;
  975.  
  976.         if (ResolveLogLibraryLinkage(
  977.                     "\p_rdLogRecordIterate",
  978.                     (UniversalProcPtr *) &upp)
  979.                 != noErr)
  980.             logRecordPtr = NULL;
  981.         else {
  982.             logRecordPtr = (*upp)(cookie);
  983.         }
  984. #else
  985.         OSErr                    status;
  986.         Boolean                    done;
  987.         RegPropertyNameBuf        property;
  988.         RegPropertyValueSize    actualSize;
  989.  
  990.         do {
  991.             status = RegistryPropertyIterate(
  992.                         &cookie->propertyIterCookie,
  993.                         property,
  994.                         &done
  995.                     );
  996.         } while (status == noErr
  997.             && done == FALSE
  998.             && CStrCmp(kReservedPropertyName, property) == 0);
  999.         if (status != noErr || done)
  1000.             logRecordPtr = NULL;
  1001.         else {
  1002.             actualSize = sizeof logRecordPtr;
  1003.             status = RegistryPropertyGet(
  1004.                         &gLogEntryID,
  1005.                         property,
  1006.                         &logRecordPtr,
  1007.                         &actualSize
  1008.                     );
  1009.             if (status != noErr || actualSize != sizeof logRecordPtr)
  1010.                 logRecordPtr = NULL;
  1011.         }
  1012. #endif /* GENERATE_GLUE */
  1013.         return (logRecordPtr);
  1014. }
  1015.  
  1016.  
  1017. #if GENERATE_GLUE
  1018.  
  1019. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  1020.  * ResolveLogLibraryLinkage
  1021.  *
  1022.  * This function is called (only on 68000 compilations) to form the Mixed Mode
  1023.  * routine descriptor. Originally, it stored the pointer in a static location (owned
  1024.  * by the caller), but this failed when called from a dcmd.
  1025.  */
  1026. static OSErr
  1027. ResolveLogLibraryLinkage(
  1028.         ConstStr255Param        symbolRDName,
  1029.         UniversalProcPtr        *uppPtr                    /* Pointer to static upp    */
  1030.     )
  1031. {
  1032.         OSErr                    status;
  1033.         CFragConnectionID        connID;
  1034.         Ptr                        mainAddr;                /* Main address: unused        */
  1035.         Str255                    errorName;                /* Fragment failure text    */
  1036.         CFragSymbolClass        symbolClass;            /* Symbol class (unused)    */                
  1037.  
  1038.         status = GetSharedLibrary(
  1039.                     kLogSharedLibraryName,
  1040.                     kPowerPCCFragArch,
  1041.                     kLoadCFrag,
  1042.                     &connID,
  1043.                     &mainAddr,
  1044.                     errorName
  1045.                 );
  1046. #if TEST_DCMD
  1047.         if (status != noErr) {
  1048.             PutSigned(status);
  1049.             PutPascalString("\p: GetSharedLibrary failed");
  1050.             PutLine();
  1051.             PutPascalString("\pCan't resolve ");
  1052.             PutPascalString(errorName);
  1053.             PutLine();
  1054.         }
  1055. #endif
  1056.         if (status == noErr) {
  1057.             /*
  1058.              * We have the library (but we've never seen this function),
  1059.              * locate its Routine Descriptor in the library
  1060.              */
  1061.             status = FindSymbol(
  1062.                     connID,
  1063.                     symbolRDName,
  1064.                     (Ptr *) uppPtr,
  1065.                     &symbolClass
  1066.                 );
  1067. #if TEST_DCMD
  1068.             if (status != noErr) {
  1069.                 PutSigned(status);
  1070.                 PutPascalString("\p: FindSymbol failed");
  1071.                 PutLine();
  1072.                 PutPascalString("\pCan't find symbol: ");
  1073.                 PutPascalString(symbolRDName);
  1074.                 PutLine();
  1075.             }
  1076. #endif
  1077.             if (status == noErr && symbolClass != kDataCFragSymbol)
  1078.                 status = paramErr;                /* Bug: name isn't a function    */
  1079.         }
  1080.         return (status);
  1081. }
  1082. #endif
  1083.  
  1084. #if GENERATE_GLUE == 0
  1085. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  1086.  * These are the only functions that know about the Name Registry -- well, except for
  1087.  * the iterators, of course.
  1088.  */
  1089.  
  1090.  
  1091. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  1092.  * CreateLogRecord
  1093.  *
  1094.  * This function manipulates the System Name Registry to create or lookup the named
  1095.  * log record.
  1096.  */
  1097.  
  1098. static LogRecordPtr
  1099. CreateLogRecord(
  1100.         const LogRecordNamePtr    logRecordNamePtr,        /* Driver Log name            */
  1101.         UInt32                    nEntries                /* Number of Log entries    */
  1102.     )
  1103. {
  1104.         OSErr                    status;
  1105.         LogRecordPtr            logRecordPtr;            /* This driver log            */
  1106.         ByteCount                logRecordSize;
  1107.  
  1108.         logRecordPtr = FindLogRecordPtr(logRecordNamePtr);
  1109.         if (logRecordPtr == NULL && gFoundLogEntryStatus == kLogEntryOK) {
  1110.             /*
  1111.              * The log record is not in the registry entry (possibly because we
  1112.              * just created it. Add this name as a new property.
  1113.              *
  1114.              * Hand-compute the LogEntryRecord size to make sure that compiler quirks
  1115.              * don't mess us up. We check that kSizeofLogEntry equals sizeof
  1116.              * (LogEntryRecord). The ANSI C Standard does not permit "sizeof" in a
  1117.              * #define statement, so this check must be made at runtime.
  1118.              *
  1119.              * Note: do not replace the hard-coded numbers by sizeof statements:
  1120.              * this strange sequence ensures that the library can be complied
  1121.              * by several compilers.
  1122.              */
  1123.             #define kSizeofLogRecordEntry                                    \
  1124.                     ( 8                            /* sizeof eventTime        */    \
  1125.                     + 4                            /* sizeof sequence        */    \
  1126.                     + 4                            /* sizeof idCode        */    \
  1127.                     + 4                            /* sizeof format        */    \
  1128.                     + (4 * kLogEntryDataSize)    /* sizeof data[]        */    \
  1129.                     )
  1130.             if (sizeof (LogEntryRecord) == kSizeofLogRecordEntry    /* Size ok?        */
  1131.              && nEntries > 0) {                                        /* Has entries?    */
  1132.                 /*
  1133.                  * We must create a new log record storing a pointer to it as a
  1134.                  * property in the Name Registry. The actual record has one extra
  1135.                  * entry to prevent the "full vs. empty" bug.
  1136.                  */
  1137.                 logRecordSize = sizeof (LogRecord)
  1138.                             + (nEntries * sizeof (LogEntryRecord));
  1139.                 logRecordPtr = (LogRecordPtr)
  1140.                             PoolAllocateResident(logRecordSize, TRUE);
  1141.                 if (logRecordPtr != NULL) {
  1142.                     status = RegistryPropertyCreate(
  1143.                                 &gLogEntryID,
  1144.                                 (RegPropertyNamePtr) logRecordNamePtr,
  1145.                                 &logRecordPtr,
  1146.                                 sizeof logRecordPtr
  1147.                             );
  1148.                     if (status != noErr) {
  1149.                         (void) PoolDeallocate((LogicalAddress) logRecordPtr);
  1150.                         logRecordPtr = NULL;
  1151.                     }
  1152.                 }
  1153.             }
  1154.         }
  1155. exit:    return (logRecordPtr);
  1156. }
  1157.  
  1158. /*
  1159.  * Find the log record, creating the log registry entry if necessary.
  1160.  */
  1161. LogRecordPtr
  1162. FindLogRecordPtr(
  1163.         const LogRecordNamePtr    logRecordNamePtr        /* Driver Log name            */
  1164.     )
  1165. {
  1166.         OSErr                    status;
  1167.         RegPropertyValueSize    actualSize;
  1168.         LogRecordPtr            logRecordPtr;
  1169.  
  1170.         logRecordPtr = NULL;
  1171.         if (logRecordNamePtr[0] != EOS                                /* real string?    */
  1172.          && CStrCmp(kReservedPropertyName, logRecordNamePtr) != 0) {/* not "name"?    */
  1173.             if (FindOrCreateLogRegistryEntryID()) {
  1174.                 actualSize = sizeof logRecordPtr;
  1175.                 status = RegistryPropertyGet(
  1176.                             &gLogEntryID,
  1177.                             (RegPropertyNamePtr) logRecordNamePtr,
  1178.                             &logRecordPtr,
  1179.                             &actualSize
  1180.                         );
  1181.                 if (status != noErr || actualSize != sizeof logRecordPtr)
  1182.                     logRecordPtr = NULL;
  1183.             }
  1184.         }
  1185.         return (logRecordPtr);
  1186. }
  1187.  
  1188. Boolean
  1189. FindOrCreateLogRegistryEntryID(void)
  1190. {
  1191.         OSErr                    status;
  1192.  
  1193.         if (gFoundLogEntryStatus == kFirstCall) {
  1194.             status = RegistryCStrEntryLookup(
  1195.                         NULL, kLogRegistryEntry, &gLogEntryID);
  1196.             if (status != noErr) {
  1197.                 status = RegistryCStrEntryCreate(
  1198.                             NULL, kLogRegistryEntry, &gLogEntryID);
  1199.             }
  1200.             gFoundLogEntryStatus = (status == noErr)
  1201.                         ? kLogEntryOK : kLogEntryFailed;
  1202.         }
  1203.         return (gFoundLogEntryStatus == kLogEntryOK);
  1204. }
  1205.  
  1206. #endif    /* Functions that are only available to the actual library */
  1207.  
  1208.  
  1209.